<?php

namespace app\data\service;

use think\admin\Service;

/**
 * 商城订单数据服务
 * Class OrderService
 * @package app\data\service
 */
class OrderService extends Service
{

    public function getInfo($id){
        return $this->app->db->name('ShopOrder')->where('id', $id)->find();
    }

    /**
     * 获取随机减免金额
     * @return float
     */
    public function getReduct(): float
    {
        return rand(1, 100) / 100;
    }

    /**
     * 同步订单关联产品的库存
     * @param string $orderNo 订单编号
     * @return boolean
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function stock(string $orderNo): bool
    {
        $map = ['order_no' => $orderNo];
        $codes = $this->app->db->name('ShopOrderItem')->where($map)->column('goods_code');
        foreach (array_unique($codes) as $code) GoodsService::instance()->stock($code);
        return true;
    }

    /**
     * 根据订单更新用户等级
     * @param string $orderNo
     * @return array|null [USER, ORDER, ENTRY]
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function upgrade(string $orderNo): ?array
    {
        // 目标订单数据
        $map = [['order_no', '=', $orderNo], ['status', '>=', 4]];
        $order = $this->app->db->name('ShopOrder')->where($map)->find();
        if (empty($order)) return null;
        // 订单用户数据
        $user = $this->app->db->name('DataUser')->where(['id' => $order['uid']])->find();
        if (empty($user)) return null;
        // 更新用户购买资格
        $entry = $this->vipEntry($order['uid']);
        // 尝试绑定代理用户
        if (empty($user['pids']) && ($order['puid1'] > 0 || $user['pid1'] > 0)) {
            $puid1 = $order['puid1'] > 0 ? $order['puid1'] : $user['pid0'];
            UserUpgradeService::instance()->bindAgent($user['id'], $puid1);
        }
        // 重置用户信息并绑定订单
        $user = $this->app->db->name('DataUser')->where(['id' => $order['uid']])->find();
        if ($user['pid1'] > 0) {
            $this->app->db->name('ShopOrder')->where(['order_no' => $orderNo])->update([
                'puid1' => $user['pid1'], 'puid2' => $user['pid2'],
            ]);
        }
        // 重新计算用户等级
        UserUpgradeService::instance()->upgrade($user['id'], true, $orderNo);
        return [$user, $order, $entry];
    }

    /**
     * 刷新用户入会礼包
     * @param integer $uid 用户UID
     * @return integer
     * @throws \think\db\exception\DbException
     */
    private function vipEntry(int $uid): int
    {
        // 检查是否购买入会礼包
        $query = $this->app->db->table('shop_order a')->join('shop_order_item b', 'a.order_no=b.order_no');
        $entry = $query->where("a.uid={$uid} and a.status>=4 and a.payment_status=1 and b.vip_entry>0")->count() ? 1 : 0;
        // 用户最后支付时间
        $query = $this->app->db->name('ShopOrder');
        $lastMap = [['uid', '=', $uid], ['status', '>=', 4], ['payment_status', '=', 1]];
        $lastDate = $query->where($lastMap)->order('payment_datetime desc')->value('payment_datetime');
        // 更新用户支付信息
        $this->app->db->name('DataUser')->where(['id' => $uid])->update([
            'buy_vip_entry' => $entry, 'buy_last_date' => $lastDate,
        ]);
        return $entry;
    }

    /**
     * 获取等级折扣比例
     * @param int $disId 折扣方案ID
     * @param int $vipCode 等级序号
     * @param float $disRate 默认比例
     * @return array [方案编号, 折扣比例]
     */
    public function discount(int $disId, int $vipCode, float $disRate = 100.00): array
    {
        if ($disId > 0) {
            $map = ['id' => $disId, 'status' => 1, 'deleted' => 0];
            $discount = $this->app->db->name('BaseUserDiscount')->where($map)->value('items');
            $disitems = json_decode($discount ?: '[]', true) ?: [];
            if (is_array($disitems) && count($disitems) > 0) foreach ($disitems as $vo) {
                if ($vo['level'] == $vipCode) $disRate = floatval($vo['discount']);
            }
        }
        return [$disId, $disRate];
    }

    /**
     * 绑定订单详情数据
     * @param array $data
     * @param boolean $from
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function buildData(array &$data = [], $from = true): array
    {
        if (empty($data)) return $data;
        // 关联发货信息
        $nobs = array_unique(array_column($data, 'order_no'));
        $trucks = $this->app->db->name('ShopOrderSend')->whereIn('order_no', $nobs)->column('*', 'order_no');
        foreach ($trucks as &$item) unset($item['id'], $item['uid'], $item['status'], $item['deleted'], $item['create_at']);
        // 关联订单产品
        $query = $this->app->db->name('ShopOrderItem')->where(['status' => 1, 'deleted' => 0]);
        $items = $query->withoutField('id,uid,status,deleted,create_at')->whereIn('order_no', $nobs)->select()->toArray();
        // 关联用户数据
        $fields = 'phone,username,nickname,headimg,status,vip_code,vip_name';
        if ($data) UserAdminService::instance()->buildByUid($data, 'uid', 'user', $fields);
        if ($from) UserAdminService::instance()->buildByUid($data, 'puid1', 'from', $fields);
        foreach ($data as &$vo) {
            [$vo['sales'], $vo['truck'], $vo['items']] = [0, $trucks[$vo['order_no']] ?? [], []];
            foreach ($items as $item) if ($vo['order_no'] === $item['order_no']) {
                $vo['sales'] += $item['stock_sales'];
                $vo['items'][] = $item;
            }
        }
        return $data;
    }


    /**
     * @param $data
     * @return array
     * 按天复利
     */
    public function calculateFl($data): array
    {
        //数据初始化
        $startAt = $data['start_at'];
        $endAt = $data['end_at'];
        $annualRate = $data['goods_annual_rate']/100;
        $dayRate = $annualRate/365;

        //起始日期当月最后一天
        $days = getDayNum($startAt,$endAt);
        $data['expect_lxflje'] =  sprintf('%.2f' , $data['money']*((1+$dayRate)**$days)-$data['money']);
        return $data;
    }
    /**
     * @param $data
     * @return array
     */
    public function calculateLx($data): array
    {
        //数据初始化
        $startAt = $data['start_at'];
        $endAt = $data['end_at'];

        $annualRate = $data['goods_annual_rate']/100;
        $monthRate = $annualRate/12;

        $data['current_month_lxje'] = 0;
        $data['full_month_lxje'] = 0;
        $data['expire_month_lxje'] = 0;

        //起始日期当月最后一天
        $lastDay = date('Y-m-t' ,strtotime($startAt));
        $firstMonthTotalDays = date('t', strtotime($startAt));
        $firstMonthRate = $monthRate/$firstMonthTotalDays;
        if($endAt > $lastDay){
            $firstMonthDays = getDayNum($startAt,$lastDay)+1;
        }else{
            $firstMonthDays = getDayNum($startAt,$endAt);
        }

        //起息当月利息金额
        $data['current_month_lxje'] = sprintf('%.2f' , $data['money']*$firstMonthDays*$firstMonthRate);
        //获取与到期月相差多少月份
        $months  = getMonthNum($startAt, $endAt);
        //完整的自然月月份
        $months--;
        if($months>-1){
            if($months>0){
                //满整月利息金额
                $data['full_month_lxje'] = sprintf('%.2f' , $data['money']*$monthRate*$months);
            }
            //到期当月第一天
            $endMonthFirstDay = date('Y-m-01', strtotime($endAt));
            $endMonthTotalDays = date('t', strtotime($endAt));
            $endMonthRate = $monthRate/$endMonthTotalDays;
            //到期月第一天与到期日期相差天数
            $endMonthDays = getDayNum($endMonthFirstDay,$endAt);
            //到期当月利息金额
            $data['expire_month_lxje'] =  sprintf('%.2f' , $data['money']*$endMonthDays*$endMonthRate);
        }
        //到期利息预估总额
        $data['expect_lxje'] =  sprintf('%.2f' , $data['current_month_lxje']+$data['full_month_lxje']+$data['expire_month_lxje']);
        return $data;
    }

    /**
     * @param $data
     * @return bool
     * @throws \think\db\exception\DbException
     */
    public function calculateLxLog($data): bool
    {
        $annualRate = $data['goods_annual_rate']/100;
        $monthRate = $annualRate/12;
        $returnLogs = [];
        $startAt = date('Y-m', strtotime($data['start_at']));
        $endAt = date('Y-m', strtotime($data['end_at']));
        if(!empty($data['id'])){
            $orderLog = $this->app->db->name('ShopOrderReturnRateLog')->where('order_id' , $data['id'])->where('status', 1)->order('month', 'desc')->find();
            if($orderLog){
                $startAt = getPurMonth($orderLog['month'], 1);
            }
            $this->app->db->name('ShopOrderReturnRateLog')->where('order_id' , $data['id'])->where('status' , 0)->delete(true);
        }
        $currentDate = date('Y-m', strtotime($startAt));
        $currentYear = explode('-',$currentDate)[0];
        $currentMonth = explode('-',$currentDate)[1];
        $monthNumber = getMonthNum($startAt, $endAt)+1;
        $currentMonthLxje = 0;
        $fullMonthLxje = 0;
        $currentLxje = $data['current_lxje'];
        $expireMonthLxje = 0;

        for($i=0;$i<$monthNumber;$i++){
            $temp = [];
            $temp['order_id'] = $data['id'];
            $newYear = $currentYear;
            $newMonth = $currentMonth+$i;
            if($newMonth > 12){
                $newYear++;
                $newMonth = $newMonth-12;
            }
            if($newMonth<10){
                $newMonth = '0'.$newMonth;
            }
            $temp['month'] = $newYear.'-'.$newMonth;
            if(isSameMonth($data['start_at'],$temp['month'])){
                $currentMonthTotalDays = date('t',strtotime($temp['month']));
                $currentMonthDayRate = $monthRate/$currentMonthTotalDays;
                $days = getDayNum($data['start_at'], date('Y-m-t', strtotime($data['start_at'])))+1;
                $temp['money'] = sprintf("%.2f", $data['money']*$days*$currentMonthDayRate);
                $currentMonthLxje = $temp['money'];
            }elseif(isSameMonth($data['end_at'],$temp['month'])){
                $endMonthTotalDays = date('t',strtotime($temp['month']));
                $endMonthDayRate = $monthRate/$endMonthTotalDays;
                $days = getDayNum(date('Y-m-01', strtotime($data['end_at'])), $data['end_at']);
                $temp['money'] = sprintf("%.2f", $data['money']*$days*$endMonthDayRate);
                $expireMonthLxje = $temp['money'];
            }else{
                $temp['money'] = sprintf("%.2f", $data['money']*$monthRate);
                $fullMonthLxje += $temp['money'];
            }
            $temp['status'] = 0;
            //兼容之前数据
            if($temp['month']<date('Y-m')){
                $currentLxje += $temp['money'];
                $temp['status'] = 1;
            }
            if(!isSameMonth($data['end_at'],$temp['month'])){
                $returnLogs[] = $temp;
            }

        }
        $expectLxje = sprintf("%.2f", $currentMonthLxje+$expireMonthLxje+$fullMonthLxje);
        $this->app->db->name('ShopOrder')
            ->where('id',$data['id'])
            ->update(
                [
                    'update_at'=>date('Y-m-d H:i:s'),
                    'expect_lxje'=> $expectLxje,
                    'current_month_lxje'=> $currentMonthLxje,
                    'expire_month_lxje'=> $expireMonthLxje,
                    'full_month_lxje'=> $fullMonthLxje,
                    'current_lxje'=> $currentLxje,
                ]
            );
        $this->app->db->name('ShopOrderReturnRateLog')->insertAll($returnLogs);
        return true;
    }
}